"""分析服务模块

负责处理脑波数据分析的业务逻辑
实现内存缓存机制，可配置的时间间隔将内存数据追加到数据库
支持新的累积数据存储模式，使用 sleep_analysis_sessions 表
"""

import json
import logging
import threading
import time
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any

from app.config import settings
from app.models.brain_wave import BrainWave
from app.models.sleep_monitoring_metrics import SleepMonitoringMetrics
from app.models.sleep_analysis_session_orm import SleepAnalysisSessionORM
from app.schemas.analysis_schemas import (
    AnalysisDataPoint, AnalysisResultRequest, AnalysisResultResponse
)

logger = logging.getLogger(__name__)


class AnalysisService:
    """分析服务类
    
    实现内存缓存机制，可配置的时间间隔将内存数据追加到数据库
    """
    
    def __init__(self):
        """初始化分析服务"""
        self._memory_cache = {}  # 内存缓存，存储最新的分析结果
        self._cache_lock = threading.Lock()  # 线程锁，保证线程安全
        self._timer = None  # 定时器
        self._cache_ttl = settings.memory_cache_ttl_seconds  # 缓存TTL配置
        self._cleanup_interval = settings.memory_cache_cleanup_interval_seconds  # 清理间隔配置
        self._start_timer()  # 启动定时器
        logger.info(f"分析服务初始化完成，内存缓存机制已启动 (TTL: {self._cache_ttl}s, 清理间隔: {self._cleanup_interval}s)")
    
    def _start_timer(self):
        """启动定时器，定期执行内存缓存清理和数据库写入"""
        if self._timer:
            self._timer.cancel()
        self._timer = threading.Timer(self._cleanup_interval, self._cleanup_and_flush)
        self._timer.daemon = True
        self._timer.start()
    
    def _cleanup_and_flush(self):
        """清理过期缓存并将数据写入数据库"""
        try:
            current_time = datetime.now()
            cutoff_time = current_time - timedelta(seconds=self._cache_ttl)
            
            with self._cache_lock:
                if not self._memory_cache:
                    logger.debug("内存缓存为空，跳过清理和写入")
                    self._start_timer()  # 重新启动定时器
                    return
                
                # 分离过期数据和有效数据
                expired_data = {}
                valid_data = {}
                
                for session_id, data in self._memory_cache.items():
                    analysis_time = data.get('analysis_time')
                    if isinstance(analysis_time, datetime) and analysis_time < cutoff_time:
                        expired_data[session_id] = data
                    else:
                        valid_data[session_id] = data
                
                # 更新内存缓存，只保留有效数据
                self._memory_cache = valid_data
                
                logger.info(f"内存缓存清理完成: 过期数据 {len(expired_data)} 条, 保留数据 {len(valid_data)} 条")
            
            # 将过期数据写入数据库
            if expired_data:
                self._write_data_to_database(expired_data)
            
        except Exception as e:
            logger.error(f"内存缓存清理失败: {str(e)}")
        finally:
            # 重新启动定时器
            self._start_timer()
    
    def _write_data_to_database(self, data_dict: Dict[str, Any]):
        """将数据写入数据库 - 使用新的累积存储模式
        
        Args:
            data_dict: 要写入的数据字典
        """
        logger.info(f"开始批量写入数据库，共 {len(data_dict)} 条记录")
        
        success_count = 0
        
        # 按会话ID分组数据点
        session_data = {}
        for cache_key, data in data_dict.items():
            session_id = data['session_id']
            if session_id not in session_data:
                session_data[session_id] = {
                    'room_id': data['room_id'],
                    'user_id': data['user_id'],
                    'data_points': []
                }
            
            # 从缓存键中提取时间戳
            try:
                timestamp_str = cache_key.split('_')[-2]  # 格式: session_id_timestamp_index
                timestamp = float(timestamp_str)
            except (IndexError, ValueError):
                timestamp = data['analysis_time'].timestamp()
            
            # 构建数据点
            data_point = {
                'timestamp': timestamp,
                'state': data['sleep_state'],
                'confidence': data['quality_score'],
                'delta': data['frequency_ratios'].get('delta_ratios', 0.0),
                'theta': data['frequency_ratios'].get('theta_ratios', 0.0),
                'alpha': (data['frequency_ratios'].get('low_alpha_ratios', 0.0) + 
                         data['frequency_ratios'].get('high_alpha_ratios', 0.0)),
                'beta': (data['frequency_ratios'].get('low_beta_ratios', 0.0) + 
                        data['frequency_ratios'].get('high_beta_ratios', 0.0)),
                'gamma': (data['frequency_ratios'].get('low_gamma_ratios', 0.0) + 
                         data['frequency_ratios'].get('mid_gamma_ratios', 0.0))
            }
            session_data[session_id]['data_points'].append(data_point)
        
        # 为每个会话写入数据
        for session_id, session_info in session_data.items():
            try:
                logger.debug(f"正在写入会话数据: session_id={session_id}, 数据点数={len(session_info['data_points'])}")
                
                # 获取或创建会话记录
                session_record = SleepAnalysisSessionORM.get_or_create_session(
                    session_id=session_id,
                    room_id=session_info['room_id'],
                    user_id=session_info['user_id']
                )
                
                # 批量添加数据点
                session_record.add_analysis_points(session_info['data_points'])
                
                # 保存到数据库
                session_record.save()
                
                success_count += 1
                logger.debug(f"会话数据已写入数据库: session_id={session_id}, "
                           f"总数据点={session_record.total_data_points}, record_id={session_record.id}")
                
            except Exception as e:
                logger.error(f"写入会话数据失败: session_id={session_id}, 错误: {str(e)}")
                continue
        
        logger.info(f"数据库写入完成，成功写入 {success_count} 个会话的数据")
        return success_count
    
    def _convert_8_to_5_frequency(self, frequency_ratios: Dict[str, float]) -> Dict[str, float]:
        """将8频域数据转换为5频域格式
        
        将数据库中存储的8频域数据（delta, theta, low_alpha, high_alpha, low_beta, high_beta, low_gamma, mid_gamma）
        转换为API返回的5频域格式（delta, theta, alpha, beta, gamma）
        
        Args:
            frequency_ratios: 8频域数据字典
            
        Returns:
            Dict[str, float]: 5频域数据字典
        """
        try:
            # 合并alpha频段（low_alpha + high_alpha）
            alpha = frequency_ratios.get('low_alpha_ratios', 0.0) + frequency_ratios.get('high_alpha_ratios', 0.0)
            
            # 合并beta频段（low_beta + high_beta）
            beta = frequency_ratios.get('low_beta_ratios', 0.0) + frequency_ratios.get('high_beta_ratios', 0.0)
            
            # 合并gamma频段（low_gamma + mid_gamma）
            gamma = frequency_ratios.get('low_gamma_ratios', 0.0) + frequency_ratios.get('mid_gamma_ratios', 0.0)
            
            return {
                'delta': frequency_ratios.get('delta_ratios', 0.0),
                'theta': frequency_ratios.get('theta_ratios', 0.0),
                'alpha': alpha,
                'beta': beta,
                'gamma': gamma
            }
        except Exception as e:
            logger.warning(f"频域数据转换失败: {str(e)}, 使用默认值")
            return {
                'delta': 0.0,
                'theta': 0.0,
                'alpha': 0.0,
                'beta': 0.0,
                'gamma': 0.0
            }
    
    def receive_analysis_result(self, request: AnalysisResultRequest) -> AnalysisResultResponse:
        """接收分析结果数据并存储到内存缓存
        
        Args:
            request: 分析结果请求，包含多个数据点
            
        Returns:
            AnalysisResultResponse: 分析结果响应
        """
        try:
            logger.info(f"接收分析结果: session_id={request.session_id}, data_points={len(request.data)}")
            
            # 处理每个数据点并存储到内存缓存
            with self._cache_lock:
                for i, data_point in enumerate(request.data):
                    # 为每个数据点创建唯一的缓存键
                    cache_key = f"{request.session_id}_{int(data_point.timestamp)}_{i}"
                    
                    # 将5频域数据转换为8频域格式（保持与数据库兼容）
                    frequency_ratios = {
                        'delta_ratios': data_point.delta,
                        'theta_ratios': data_point.theta,
                        'low_alpha_ratios': data_point.alpha * 0.6,  # 将alpha分为low和high
                        'high_alpha_ratios': data_point.alpha * 0.4,
                        'low_beta_ratios': data_point.beta * 0.7,   # 将beta分为low和high
                        'high_beta_ratios': data_point.beta * 0.3,
                        'low_gamma_ratios': data_point.gamma * 0.6, # 将gamma分为low和mid
                        'mid_gamma_ratios': data_point.gamma * 0.4
                    }
                    
                    self._memory_cache[cache_key] = {
                        'session_id': request.session_id,
                        'room_id': request.room_id,
                        'user_id': request.user_id,
                        'analysis_time': datetime.fromtimestamp(data_point.timestamp),
                        'sleep_state': data_point.state,
                        'frequency_ratios': frequency_ratios,
                        'quality_score': data_point.confidence,
                        'recommendations': []  # 暂时为空列表
                    }
            
            logger.info(f"分析结果已存储到内存缓存: session_id={request.session_id}, 共{len(request.data)}个数据点")
            
            return AnalysisResultResponse(
                success=True,
                id=request.session_id,
                message=f"分析结果已存储到内存缓存，共{len(request.data)}个数据点"
            )
            
        except Exception as e:
            logger.error(f"接收分析结果失败: {str(e)}")
            return AnalysisResultResponse(
                success=False,
                id=request.session_id if hasattr(request, 'session_id') else "unknown",
                message=f"存储失败: {str(e)}"
            )
    

    async def get_realtime_status_range(
        self, 
        room_ids: List[str], 
        last_query_timestamp: float
    ) -> Dict[str, Any]:
        """获取指定时间范围内的多房间实时状态数据，按房间ID分类返回
        
        根据房间ID列表和上次查询时间戳，返回按房间ID分类的状态数据
        每个房间的数据按时间戳排序形成列表，便于前端查询渲染
        
        Args:
            room_ids: 房间ID列表
            last_query_timestamp: 上次查询时间戳（Unix时间戳）
            
        Returns:
            dict: 按房间ID分类的状态数据，每个房间包含按时间戳排序的数据列表
            dict: 包含多房间状态数据列表的响应
        """
        try:
            logger.info(f"查询时间范围内状态数据: room_ids={room_ids}, "
                       f"last_timestamp={last_query_timestamp}")
            
            # 将Unix时间戳转换为datetime对象
            from datetime import datetime
            
            # 检查时间戳格式并转换
            # 如果是毫秒级时间戳（13位数字），转换为秒级
            if last_query_timestamp > 1e12:  # 毫秒级时间戳
                timestamp_seconds = last_query_timestamp / 1000.0
                logger.debug(f"检测到毫秒级时间戳，转换: {last_query_timestamp} -> {timestamp_seconds}")
            else:  # 秒级时间戳
                timestamp_seconds = last_query_timestamp
                logger.debug(f"使用秒级时间戳: {timestamp_seconds}")
            
            # 验证时间戳有效性
            try:
                last_query_time = datetime.fromtimestamp(timestamp_seconds)
            except (ValueError, OSError) as e:
                logger.error(f"无效的时间戳: {last_query_timestamp}, 转换后: {timestamp_seconds}, 错误: {str(e)}")
                raise ValueError(f"无效的时间戳格式: {last_query_timestamp}")
            
            current_time = datetime.now()
            
            # 从内存缓存中查找符合条件的数据
            cached_data = []
            with self._cache_lock:
                for cache_key, data in self._memory_cache.items():
                    if data['room_id'] in room_ids:
                        
                        # 检查时间范围
                        analysis_time = data.get('analysis_time')
                        if isinstance(analysis_time, datetime):
                            if analysis_time > last_query_time:
                                data_copy = data.copy()
                                # 使用数据中存储的原始session_id，而不是cache_key
                                data_copy['session_id'] = data['session_id']
                                cached_data.append(data_copy)
            
            # 使用纯内存缓存数据，不查询数据库
            all_data = cached_data
            
            # 按时间戳排序并去重（基于session_id和analysis_time）
            seen = set()
            unique_data = []
            for data in sorted(all_data, key=lambda x: x['analysis_time']):
                key = (data['session_id'], data['analysis_time'])
                if key not in seen:
                    seen.add(key)
                    unique_data.append(data)
            
            # 转换为返回格式，按room_id分类
            room_data = {}
            for data in unique_data:
                try:
                    # 将8频域数据转换为5频域格式
                    frequency_bands = self._convert_8_to_5_bands(data['frequency_ratios'])
                    
                    item = {
                        'session_id': data['session_id'],
                        'timestamp': data['analysis_time'].timestamp() if isinstance(data['analysis_time'], datetime) else data['analysis_time'],
                        'analysis_time': data['analysis_time'].isoformat() if isinstance(data['analysis_time'], datetime) else data['analysis_time'],
                        'sleep_state': data['sleep_state'],
                        'frequency_bands': frequency_bands,
                        'quality_score': data['quality_score']
                    }
                    
                    # 按room_id分类
                    room_id = data['room_id']
                    if room_id not in room_data:
                        room_data[room_id] = []
                    room_data[room_id].append(item)
                    
                except Exception as e:
                    logger.warning(f"转换数据项失败: {str(e)}")
                    continue
            
            # 对每个房间的数据按时间戳排序
            for room_id in room_data:
                room_data[room_id].sort(key=lambda x: x['timestamp'])
            
            logger.info(f"时间范围状态查询成功: room_ids={room_ids}, "
                       f"found_rooms={len(room_data)}, total_records={sum(len(data) for data in room_data.values())}, "
                       f"memory_cached={len(cached_data)}")
            
            return room_data
            
        except ValueError as e:
            logger.warning(f"时间范围状态查询参数错误: {str(e)}")
            raise ValueError(str(e))
        except Exception as e:
            logger.error(f"时间范围状态查询失败: room_ids={room_ids}, error={str(e)}")
            raise Exception(f"时间范围状态查询失败: {str(e)}")
    
    def _convert_8_to_5_bands(self, frequency_ratios: Dict[str, float]) -> Dict[str, float]:
        """将8频域数据转换为5频域格式
        
        8频域: delta, theta, low_alpha, high_alpha, low_beta, high_beta, low_gamma, mid_gamma
        5频域: delta, theta, alpha, beta, gamma
        
        Args:
            frequency_ratios: 8频域数据字典
            
        Returns:
            dict: 5频域数据字典
        """
        try:
            # 获取8频域数据，如果不存在则使用默认值0.0
            # 注意：数据库中存储的字段名是复数形式（ratios）
            delta = frequency_ratios.get('delta_ratios', 0.0)
            theta = frequency_ratios.get('theta_ratios', 0.0)
            low_alpha = frequency_ratios.get('low_alpha_ratios', 0.0)
            high_alpha = frequency_ratios.get('high_alpha_ratios', 0.0)
            low_beta = frequency_ratios.get('low_beta_ratios', 0.0)
            high_beta = frequency_ratios.get('high_beta_ratios', 0.0)
            low_gamma = frequency_ratios.get('low_gamma_ratios', 0.0)
            mid_gamma = frequency_ratios.get('mid_gamma_ratios', 0.0)
            
            # 合并频域
            alpha = low_alpha + high_alpha  # Alpha = 低Alpha + 高Alpha
            beta = low_beta + high_beta     # Beta = 低Beta + 高Beta
            gamma = low_gamma + mid_gamma   # Gamma = 低Gamma + 中Gamma
            
            # 构建5频域结果
            result = {
                'delta': round(delta, 4),
                'theta': round(theta, 4),
                'alpha': round(alpha, 4),
                'beta': round(beta, 4),
                'gamma': round(gamma, 4)
            }
            
            logger.debug(f"8频域转5频域完成: {result}")
            return result
            
        except Exception as e:
            logger.error(f"频域转换失败: {str(e)}")
            # 返回默认的5频域数据
            return {
                'delta': 0.0,
                'theta': 0.0,
                'alpha': 0.0,
                'beta': 0.0,
                'gamma': 0.0
            }
    
    async def get_analysis_history(
        self,
        session_id: Optional[str] = None,
        room_id: Optional[str] = None,
        user_id: Optional[str] = None,
        start_time: Optional[str] = None,
        end_time: Optional[str] = None,
        limit: int = 100
    ) -> Dict[str, Any]:
        """获取分析结果历史记录
        
        Args:
            session_id: 会话ID
            room_id: 房间ID
            user_id: 用户ID
            start_time: 开始时间
            end_time: 结束时间
            limit: 返回记录数量限制
            
        Returns:
            dict: 分析结果历史记录数据
        """
        try:
            logger.info(f"查询分析历史记录: session_id={session_id}, room_id={room_id}, "
                       f"user_id={user_id}, start_time={start_time}, end_time={end_time}, limit={limit}")
            
            # 构建查询条件
            query = SleepMonitoringMetrics.select()
            
            if session_id:
                query = query.where(SleepMonitoringMetrics.session_id == session_id)
            if room_id:
                query = query.where(SleepMonitoringMetrics.room_id == room_id)
            if user_id:
                query = query.where(SleepMonitoringMetrics.user_id == user_id)
            
            # 处理时间范围查询
            if start_time:
                try:
                    start_dt = datetime.fromisoformat(start_time.replace('Z', '+00:00'))
                    query = query.where(SleepMonitoringMetrics.analysis_time >= start_dt)
                except ValueError as e:
                    logger.warning(f"开始时间格式错误: {start_time}, error: {str(e)}")
                    
            if end_time:
                try:
                    end_dt = datetime.fromisoformat(end_time.replace('Z', '+00:00'))
                    query = query.where(SleepMonitoringMetrics.analysis_time <= end_dt)
                except ValueError as e:
                    logger.warning(f"结束时间格式错误: {end_time}, error: {str(e)}")
            
            # 执行查询，按时间倒序排列
            results = list(query.order_by(SleepMonitoringMetrics.analysis_time.desc()).limit(limit))
            
            # 转换为响应格式
            history_data = []
            for record in results:
                try:
                    # 解析频段数据
                    frequency_ratios = {}
                    if record.frequency_ratios:
                        try:
                            frequency_ratios = json.loads(record.frequency_ratios)
                        except json.JSONDecodeError:
                            logger.warning(f"频段数据JSON解析失败: {record.session_id}")
                    
                    # 转换为5频域格式
                    frequency_bands = self._convert_8_to_5_frequency(frequency_ratios)
                    
                    # 解析建议数据
                    recommendations = []
                    if record.recommendations:
                        try:
                            recommendations = json.loads(record.recommendations)
                        except json.JSONDecodeError:
                            logger.warning(f"建议数据JSON解析失败: {record.session_id}")
                    
                    data_item = {
                        "session_id": record.session_id,
                        "room_id": record.room_id,
                        "user_id": record.user_id,
                        "timestamp": record.analysis_time.timestamp() if record.analysis_time else None,
                        "analysis_time": record.analysis_time.isoformat() if record.analysis_time else None,
                        "state": record.sleep_state,
                        "confidence": record.quality_score,
                        "delta": frequency_bands.get('delta', 0.0),
                        "theta": frequency_bands.get('theta', 0.0),
                        "alpha": frequency_bands.get('alpha', 0.0),
                        "beta": frequency_bands.get('beta', 0.0),
                        "gamma": frequency_bands.get('gamma', 0.0),
                        "quality_score": record.quality_score,
                        "recommendations": recommendations,
                        "create_time": record.created_at.isoformat() if record.created_at else None
                    }
                    history_data.append(data_item)
                    
                except Exception as e:
                    logger.warning(f"转换历史记录失败: {record.session_id}, error: {str(e)}")
                    continue
            
            logger.info(f"查询分析历史记录成功: 找到{len(history_data)}条记录")
            
            return {
                "status": "success",
                "data": history_data,
                "total": len(history_data),
                "limit": limit
            }
            
        except Exception as e:
            logger.error(f"查询分析历史记录失败: {str(e)}")
            raise Exception(f"查询分析历史记录失败: {str(e)}")
    
    def force_flush_cache(self):
        """手动强制刷新缓存到数据库"""
        logger.info("手动触发缓存刷新")
        self._cleanup_and_flush()
